package com.cskaoyan.javase.oop1._9block._2building;

/**
 * @description: 构造代码块
 * @author: wuguidong@cskaoyan.onaliyun.com
 **/

/**
 * 构造代码块: 定义在成员位置的代码块
 * 语法: {}
 * 作用: 随着构造器的执行而执行,所以根据这一特点,构造代码块也经常用来给成员变量赋值
 *
 * 总结一下目前为止,给成员变量赋值的方式:
 *      创建对象过程中:
 *      1,默认初始化,具有默认值
 *      2,显式赋值
 *      3,构造器赋值
 *      4,构造代码块赋值
 *
 *      创建对象后:
 *      1,对象名点赋值
 *      2,调用成员方法,然后赋值(前提是该方法是给变量赋值)
 *
 * 我们研究创建对象过程中,成员变量的赋值顺序:
 *      1,永远的第一步: 默认初始化,具有默认值
 *      2,永远的最后一步: 构造器赋值
 *      3,"掐头去尾",我们需要研究显式赋值/构造代码块赋值谁先谁后?
 *          通过代码结果,我们发现: 显式赋值/构造代码块赋值的顺序是按照代码的书写顺序执行
 *          谁在书写顺序的上面,谁就先执行,反之后执行
 *
 * 我们查看反编译class文件,发现编译后的代码不存在构造代码块这种结构,编译器会根据代码的书写顺序,智能得将显式赋值或者构造代码块当中的代码,加入所有构造器的前几行,所谓智能是为了保证:
 *      1,按照代码书写顺序,执行显式赋值和构造代码块
 *      2,构造器永远最后执行
 *
 * 根据构造代码的这种原理,我们有以下注意事项:
 *      1,构造代码块会加入所有的构造器,只要是new对象,构造代码块都会执行
 *      2,不建议把构造代码块写在显式赋值的上面,因为首先显得很奇怪,
 *          其次也不要把代码的结果变成依赖这种随机的因素
 *      3,构造代码块中的代码要放入构造器的首几行，所以在同一个类中：
 *          构造代码块总是先于它的构造器而执行
 *
 *  ### 3.4 总结
 *
 * > 总结一下到目前为止，创建对象过程中可能碰到的结构的执行顺序：
 * new对象过程中，各种结构的执行顺序：
 * 1. 对象结构存在后就进行默认初始化，所有成员变量都具有默认值后，再开始其余赋值操作
 *
 * 2. 找到new对象的那个构造器，
 *    - 如果它的首行显式地调用了另一个构造器
 *      （注：显式调用构造器可以使用this、super两个关键字，this已经学习，super后面学习）
 *      - 那么程序会先跳转到那个构造器，但是不会立刻执行，而是：
 *        - 按照类中构造代码块和显式赋值的代码书写顺序，从上到下执行其中的代码，执行完毕后：
 *      - 跳转回this或者super执行的构造器，执行完毕后：
 *      - 最终跳转回new对象构造器，执行完毕后，创建对象结束
 *    - 如果它的首行没有显式调用另一个构造器
 *      - 那么会先从上到下执行构造代码块和显式赋值代码，执行完毕后：
 *      - 跳转回new对象构造器，执行完毕后，创建对象结束
 * 3. 以上总结，没有引入继承的概念，并不全面，我们会在继承中补全它
 *
 * 实践用途:
 *      1,如果成员变量的赋值依赖于一个比较复杂的算法,不是一句显式赋值就能完成的,就可以使用构造代码块赋值
 *      2,"提取公因式"把每个构造器都需要访问的语句 提取到构造代码块中
 *
 */
public class Demo {
    public static void main(String[] args) {
        /*Phone p = new Phone(3000);
        System.out.println(p.price); //3000*/

        Phone p = new Phone(3000,"小米");
        System.out.println(p.price);

        Phone p2 = new Phone();
    }
}

class Phone {

    double price = 1000; //显式赋值
    String brand = "红米Note"; //品牌
    static int a = 10;


    //构造代码块赋值
    {
        price = 2000;
        test();
        System.out.println(this);
        System.out.println("我创建了一个Phone对象");

        //构造代码块能否给静态成员变量赋值?
        //可以,因为类加载已经完毕了
        Phone.a = 100;
        //好不好? 依赖于创建对象完成静态成员变量的赋值不合适,需要使用静态代码块给静态变量赋值
    }

    public void test(){}

    public Phone() {
        //System.out.println("我创建了一个Phone对象");
    }

    public Phone(double price) {
        //System.out.println("我创建了一个Phone对象");
        this.price = price;
    }

    public Phone(double price, String brand) {
        this(price);
        //System.out.println("我创建了一个Phone对象");
        this.brand = brand;
    }
}